using System;
using System.Collections.Generic;
using OracleInternal.Common;
using OracleInternal.ServiceObjects;

namespace OracleInternal.TTC.Accessors
{
	internal class TTCLobAccessor : Accessor
	{
		internal const int MAX_LENGTH = int.MaxValue;

		internal long m_internalInitialLOBFS;

		private LobPrefetchContext m_lobPrefetchCtx;

		internal bool m_isDefineDone;

		private int[] m_tempIntArr = new int[1];

		internal List<ArraySegment<byte>>[] m_lobLocators;

		internal LobPrefetchInfo m_prefetchInfo;

		internal List<ArraySegment<byte>>[] m_dataThroughLobArrayRead;

		private bool m_bLOBArrayFetchRequired;

		internal TTCLobAccessor(ColumnDescribeInfo colMetaData, MarshallingEngine marshallingEngine, bool bForBind, long internalInitialLOBFS, bool bDefineDone, bool bLOBArrayFetchRequired, int numRowsRequested)
			: base(colMetaData, marshallingEngine, bForBind)
		{
			m_internalInitialLOBFS = internalInitialLOBFS;
			if (!bForBind)
			{
				InitForDataAccess(colMetaData.m_maxLength);
			}
			m_totalLengthOfData = new List<int>();
			if (m_RowDataSegments == null)
			{
				m_RowDataSegments = new List<List<ArraySegment<byte>>>();
			}
			m_lobLocators = new List<ArraySegment<byte>>[numRowsRequested];
			m_isDefineDone = bDefineDone;
			m_bLOBArrayFetchRequired = bLOBArrayFetchRequired;
			if (m_bLOBArrayFetchRequired)
			{
				m_prefetchInfo = new LobPrefetchInfo(numRowsRequested);
				m_dataThroughLobArrayRead = new List<ArraySegment<byte>>[numRowsRequested];
			}
		}

		internal override void Initialize(ColumnDescribeInfo colMetaData, MarshallingEngine marshallingEngine, bool bForBind)
		{
			m_lobPrefetchCtx = null;
			base.Initialize(colMetaData, marshallingEngine, bForBind);
		}

		internal void ReInit(bool bLOBArrayFetchRequired, long initialLOBFetchSize, int numRowsRequested)
		{
			m_lastRowProcessed = 0;
			m_bLOBArrayFetchRequired = bLOBArrayFetchRequired;
			m_internalInitialLOBFS = initialLOBFetchSize;
			if (m_lobLocators == null || m_lobLocators.Length < numRowsRequested)
			{
				m_lobLocators = new List<ArraySegment<byte>>[numRowsRequested];
			}
			if (bLOBArrayFetchRequired)
			{
				if (m_prefetchInfo == null)
				{
					m_prefetchInfo = new LobPrefetchInfo(numRowsRequested);
				}
				else
				{
					m_prefetchInfo.ReInit(numRowsRequested);
				}
				if (m_dataThroughLobArrayRead == null || m_dataThroughLobArrayRead.Length < numRowsRequested)
				{
					m_dataThroughLobArrayRead = new List<ArraySegment<byte>>[numRowsRequested];
				}
			}
		}

		internal override void InitForDataAccess(int max_len)
		{
			m_byteLength = max_len;
		}

		internal override bool IsNullIndicatorSet(int currentRow)
		{
			return m_totalLengthOfData[currentRow] == 0;
		}

		internal void ReadPrefetchInformation()
		{
			List<ArraySegment<byte>> dataSegments = null;
			int length = 0;
			int length2 = 0;
			int maxSize = (int)m_internalInitialLOBFS;
			if (m_bLOBArrayFetchRequired)
			{
				m_prefetchInfo.m_totalLobSizeInDB[m_lastRowProcessed] = m_marshallingEngine.UnmarshalSB8();
				m_prefetchInfo.m_chunkSize = (int)m_marshallingEngine.UnmarshalUB4();
				if (m_internalInitialLOBFS <= 0)
				{
					return;
				}
				if (m_definedColumnType == OraType.ORA_OCICLobLocator)
				{
					if (1 == m_marshallingEngine.UnmarshalUB1())
					{
						m_prefetchInfo.m_bDbVaryingWidth = true;
					}
					if (m_prefetchInfo.m_bDbVaryingWidth)
					{
						m_prefetchInfo.m_clobCharSet = (short)m_marshallingEngine.UnmarshalUB2();
					}
					m_prefetchInfo.m_clobFormOfUse = (byte)m_marshallingEngine.UnmarshalUB1();
					maxSize = (m_prefetchInfo.m_bDbVaryingWidth ? ((int)m_internalInitialLOBFS * 2) : ((m_prefetchInfo.m_clobFormOfUse != 1) ? ((int)m_internalInitialLOBFS * m_marshallingEngine.m_nCharSetConv.MaxBytesPerChar) : ((int)m_internalInitialLOBFS * m_marshallingEngine.m_dbCharSetConv.MaxBytesPerChar)));
					maxSize = ((maxSize < int.MaxValue) ? maxSize : int.MaxValue);
				}
				m_marshallingEngine.m_oraBufRdr.StartAccumulatingColumnData(null, 0);
				m_marshallingEngine.UnmarshalCLR_ScanOnly(maxSize, out dataSegments, ref length2);
				m_prefetchInfo.m_prefetchedData[m_lastRowProcessed] = dataSegments;
				m_prefetchInfo.m_prefetchedDataLength[m_lastRowProcessed] = length2;
				m_marshallingEngine.m_oraBufRdr.StopAccumulatingColumnData();
				return;
			}
			m_marshallingEngine.UnmarshalSB8();
			m_marshallingEngine.UnmarshalUB4(bIgnoreData: true);
			if (m_internalInitialLOBFS <= 0)
			{
				return;
			}
			if (m_definedColumnType == OraType.ORA_OCICLobLocator)
			{
				bool flag = false;
				if (1 == m_marshallingEngine.UnmarshalUB1())
				{
					flag = true;
				}
				if (flag)
				{
					m_marshallingEngine.UnmarshalUB2(bIgnoreData: true);
				}
				short num = m_marshallingEngine.UnmarshalUB1(bIgnoreData: true);
				maxSize = (flag ? ((int)m_internalInitialLOBFS * 2) : ((1 != num) ? ((int)m_internalInitialLOBFS * m_marshallingEngine.m_nCharSetConv.MaxBytesPerChar) : ((int)m_internalInitialLOBFS * m_marshallingEngine.m_dbCharSetConv.MaxBytesPerChar)));
			}
			m_marshallingEngine.UnmarshalCLR_ScanOnly(maxSize, out dataSegments, ref length);
		}

		internal void ReadPrefetchInformation(DataUnmarshaller dataUnmarshaller, bool bNotNull, int currentRow, bool bIgnorePrefetchData)
		{
			long internalInitialLOBFS = m_internalInitialLOBFS;
			int length = 0;
			long num = 0L;
			int chunkSize = 0;
			bool flag = false;
			short clobCharSet = 0;
			byte clobFormOfUse = 0;
			byte[] array = null;
			long num2 = 0L;
			try
			{
				if (!bNotNull)
				{
					return;
				}
				num = dataUnmarshaller.UnmarshalSB8();
				num2 = ((num < m_internalInitialLOBFS) ? num : m_internalInitialLOBFS);
				chunkSize = (int)dataUnmarshaller.UnmarshalUB4();
				if (m_internalInitialLOBFS <= 0)
				{
					return;
				}
				if (m_definedColumnType == OraType.ORA_OCICLobLocator)
				{
					internalInitialLOBFS = num2;
					if (1 == dataUnmarshaller.UnmarshalUB1())
					{
						flag = true;
					}
					if (flag)
					{
						clobCharSet = (short)dataUnmarshaller.UnmarshalUB2();
					}
					clobFormOfUse = (byte)dataUnmarshaller.UnmarshalUB1();
					long num3 = 0L;
					num3 = ((!flag) ? (internalInitialLOBFS * m_marshallingEngine.m_dbCharSetConv.MaxBytesPerChar) : (internalInitialLOBFS * 2));
					num2 = (int)((num3 < int.MaxValue) ? num3 : int.MaxValue);
				}
				array = new byte[num2];
				dataUnmarshaller.UnmarshalCLR((int)num2, array, ref length);
			}
			finally
			{
				if (!bIgnorePrefetchData)
				{
					if (m_lobPrefetchCtx == null)
					{
						m_lobPrefetchCtx = new LobPrefetchContext();
					}
					m_lobPrefetchCtx.m_bDbVaryingWidth = flag;
					m_lobPrefetchCtx.m_chunkSize = chunkSize;
					m_lobPrefetchCtx.m_clobCharSet = clobCharSet;
					m_lobPrefetchCtx.m_clobFormOfUse = clobFormOfUse;
					m_lobPrefetchCtx.m_lobPrefetchData = array;
					m_lobPrefetchCtx.m_lobDataLength = length;
					m_lobPrefetchCtx.m_totalLobSize = num;
				}
			}
		}

		internal override void UnmarshalColumnData()
		{
			List<ArraySegment<byte>> dataSegments = null;
			int length = 0;
			if (m_bNullByDescribe)
			{
				return;
			}
			m_marshallingEngine.m_oraBufRdr.m_bParsingColumnData = true;
			m_marshallingEngine.m_oraBufRdr.m_bMarkStartOffsetForColData = true;
			int num = (int)m_marshallingEngine.UnmarshalUB4();
			if (m_isDefineDone && !m_bForBind && m_definedColumnType != OraType.ORA_OCIBFileLocator && m_marshallingEngine.DBVersion >= 11100 && num > 0)
			{
				ReadPrefetchInformation();
			}
			try
			{
				if (num > 0)
				{
					try
					{
						m_marshallingEngine.m_oraBufRdr.StartAccumulatingMyData(m_lobLocators, m_lastRowProcessed);
						m_marshallingEngine.UnmarshalCLR_ScanOnly(num, out dataSegments, ref length);
					}
					finally
					{
						m_marshallingEngine.m_oraBufRdr.StopAccumulatingColumnData();
					}
				}
				else
				{
					m_marshallingEngine.m_oraBufRdr.m_colDataStartOffset[m_marshallingEngine.m_oraBufRdr.m_colDataStartOffsetIndexToUpdate] = -1;
					if (m_lobLocators[m_lastRowProcessed] != null && m_lobLocators[m_lastRowProcessed].Count > 0)
					{
						m_lobLocators[m_lastRowProcessed].Clear();
					}
				}
			}
			finally
			{
				m_marshallingEngine.m_oraBufRdr.m_bParsingColumnData = false;
				m_marshallingEngine.m_oraBufRdr.m_bMarkStartOffsetForColData = false;
			}
			if (m_totalLengthOfData.Count > m_lastRowProcessed)
			{
				m_totalLengthOfData[m_lastRowProcessed] = length;
			}
			else
			{
				m_totalLengthOfData.Add(length);
			}
			m_lastRowProcessed++;
		}

		internal override bool UnmarshalOneRow()
		{
			List<ArraySegment<byte>> dataSegments = null;
			int length = 0;
			bool flag = true;
			if (!m_bNullByDescribe)
			{
				int num = (int)m_marshallingEngine.UnmarshalUB4();
				if (m_isDefineDone && !m_bForBind && m_definedColumnType != OraType.ORA_OCIBFileLocator && m_marshallingEngine.DBVersion >= 11100 && num > 0)
				{
					ReadPrefetchInformation();
				}
				if (num > 0)
				{
					try
					{
						flag = m_marshallingEngine.m_oraBufRdr.StartAccumulatingColumnData(m_RowDataSegments, m_lastRowProcessed);
						m_marshallingEngine.UnmarshalCLR_ScanOnly(num, out dataSegments, ref length);
					}
					finally
					{
						m_marshallingEngine.m_oraBufRdr.StopAccumulatingColumnData();
					}
				}
				if (m_bForBind && -1 == m_marshallingEngine.ProcessIndicator(num <= 0, num))
				{
					num = 0;
				}
			}
			if (flag)
			{
				m_RowDataSegments.Add(dataSegments);
				m_totalLengthOfData.Add(length);
			}
			else
			{
				m_RowDataSegments[m_lastRowProcessed] = dataSegments;
				m_totalLengthOfData[m_lastRowProcessed] = length;
			}
			m_lastRowProcessed++;
			return false;
		}

		internal byte[] GetLobLocator(int currentRow)
		{
			byte[] array = null;
			List<ArraySegment<byte>> list = ((!m_bForBind) ? m_lobLocators[currentRow] : m_RowDataSegments[currentRow]);
			int num = m_totalLengthOfData[currentRow];
			if (num > 0 && list != null && list.Count > 0)
			{
				array = new byte[num];
				Accessor.CopyDataToUserBuffer(list, 0, array, 0, num);
			}
			return array;
		}

		internal bool AbstractOrTempLOB(int currentRow)
		{
			List<ArraySegment<byte>> list = null;
			if (m_bForBind)
			{
				if (m_RowDataSegments.Count > currentRow)
				{
					list = m_RowDataSegments[currentRow];
				}
			}
			else if (m_lobLocators.Length > currentRow)
			{
				list = m_lobLocators[currentRow];
			}
			if (list != null && list.Count > 0)
			{
				if ((Accessor.GetValueAt(list, 4) & 0x40) == 64)
				{
					return true;
				}
				if ((Accessor.GetValueAt(list, 7) & 1) == 1)
				{
					return true;
				}
			}
			return false;
		}

		internal override byte[] GetByteRepresentation(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex)
		{
			return GetLobLocator(currentRow);
		}

		internal void GetLobData(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, out byte[] lobLocator, out LobPrefetchContext prefetchCtx)
		{
			lobLocator = null;
			if (!m_bNullByDescribe)
			{
				dataUnmarshaller.StartAccumulatingColumnData(currentRow, columnIndex, m_colDataSegments);
				int num = (int)dataUnmarshaller.UnmarshalUB4();
				if (m_isDefineDone && !m_bForBind && m_definedColumnType != OraType.ORA_OCIBFileLocator && m_marshallingEngine.DBVersion >= 11100)
				{
					ReadPrefetchInformation(dataUnmarshaller, num > 0, currentRow, bIgnorePrefetchData: false);
				}
				int length = 0;
				if (num > 0)
				{
					lobLocator = new byte[num];
					dataUnmarshaller.UnmarshalCLR(num, lobLocator, ref length);
				}
				dataUnmarshaller.StopAccumulatingColumnData();
			}
			prefetchCtx = m_lobPrefetchCtx;
		}

		internal long GetTotalLobLengthInDB(DataUnmarshaller dataUnmarshaller, int currentRow, int columnIndex, bool bLOBArrayReadDone)
		{
			long result = 0L;
			if (bLOBArrayReadDone)
			{
				result = m_prefetchInfo.m_totalLobSizeInDB[currentRow];
			}
			else
			{
				dataUnmarshaller.StartAccumulatingColumnData(currentRow, columnIndex, m_colDataSegments);
				if (!m_bNullByDescribe && (int)dataUnmarshaller.UnmarshalUB4() > 0 && m_isDefineDone && !m_bForBind && m_definedColumnType != OraType.ORA_OCIBFileLocator && m_marshallingEngine.DBVersion >= 11100)
				{
					result = dataUnmarshaller.UnmarshalSB8();
				}
				dataUnmarshaller.StopAccumulatingColumnData();
			}
			return result;
		}

		internal void GetLOBInfoForArrayRead(int rowIdx, out long prefetchedDataLength, out byte[] lobLocator, out long dataLengthInDB)
		{
			prefetchedDataLength = m_prefetchInfo.m_prefetchedDataLength[rowIdx];
			dataLengthInDB = m_prefetchInfo.m_totalLobSizeInDB[rowIdx];
			lobLocator = GetLobLocator(rowIdx);
		}

		internal void GetLOBPrefetchInfo(int rowIdx, out List<ArraySegment<byte>> prefetchedData, out long prefetchedDataLength, out long dataLengthInDB, out bool bIsNClob)
		{
			prefetchedData = m_prefetchInfo.m_prefetchedData[rowIdx];
			prefetchedDataLength = m_prefetchInfo.m_prefetchedDataLength[rowIdx];
			dataLengthInDB = m_prefetchInfo.m_totalLobSizeInDB[rowIdx];
			bIsNClob = m_prefetchInfo.m_clobFormOfUse == 2;
		}
	}
}
